<?php
/**
 * 通用第三方登录类
 * @author Veris
 * @version 1.0
 * @copyright http://www.mostclan.com
 * @获取用户信息步骤：
 * @1.准备CSRF令牌（防止CSRF攻击），登录，成功后跳转到回调域
 * @2.验证令牌，获取到code，请求获取AccessToken
 * @3.获取到AccessToken，请求获取openId
 * @4.获取到OpenID，可用OpenID获取用户信息
 */
namespace mcOAuth;
abstract class OAuth{
    protected $config;
    protected $AuthorizeCode;
    protected $AccessToken;
    protected $OpenID;
    protected $AuthorizeState; //CSRF令牌

    private function __construct($config){
        $this->config = $config;
    }

    /**
     * 获取一个实例
     */
    static public function getInstance($config){
        static $_instance =array();
        $type      = strtolower($config['channel']);
        $class     ='\\mcOAuth\\Driver\\'.$type;
        $_instance =new $class($config);
        return $_instance;
    }

    /**
     * 登录
     */
    public function login(){
        $this->AuthorizeState=$this->createToken();
        setcookie('A_S',$this->AuthorizeState,time()+600,'/');
        $url=$this->buildAuthorizeCodeURL();
        header('Location:'.$url);
    }

    /**
     * 注销
     */
    public function logout(){
        setcookie('A_S',null,time()-1,'/');
        setcookie('sns',null,time()-1,'/');
    }

    /**
     * 获取AccessToken
     */
    public function getAccessToken($ignore=false){
        $this->AuthorizeCode=isset($_GET['code'])?$_GET['code']:'';
        if($ignore===false && isset($_GET['state'])){
            $state=$_GET['state'];
            if(empty($this->AuthorizeCode)){
                exception('请检查authorization code！');
            }
            if($state!==$_COOKIE['A_S']){
                exception('state错误，请重试！');
            }
        }
        $data=$this->doGetAccessToken();
        if(!empty($data)){
            setcookie('sns',json_encode($data),time()+7776000,'/');
        }
        return $data;
    }

    /**
     * 获取OpenID
     */
    public function getOpenID(){
        if(empty($this->AccessToken)){
            $this->getAccessToken();
        }
        if(empty($this->OpenID)){
            return $this->doGetOpenID();
        }
        return $this->OpenID;
    }

    /**
     * 获取用户信息
     */
    public function getUserInfo(){
        if(empty($this->AccessToken)){
            $this->getAccessToken();
        }
        $data=$this->doGetUserInfo();
        return $data;
    }

    /**
     * 生成CSRF令牌
     */
    protected function createToken(){
        return md5(uniqid(rand(),true));
    }

    /**
     * 构建API地址
     */
    protected function buildAPI($resource,$params){
        return $this->API_URL . $resource . '?' . http_build_query($params);
    }

    /**
     * API请求方法
     */
    protected function requestAPI($url,$params=array(),$type='GET',$headers=array()){
        $url=$this->API_URL.$url;
        $ch = curl_init();
        if($type=='GET' && !empty($params)){
            $url.='?'.http_build_query($params);
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        if(!empty($headers) && is_array($headers)){
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); //忽略SSL证书
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); //忽略SSL证书
        if($type=='POST'){
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
        }
        curl_exec($ch);
        $data=curl_multi_getcontent($ch);
        curl_close($ch);
        return $data;
    }

    abstract protected function buildAuthorizeCodeURL();
    abstract protected function doGetAccessToken();
    abstract protected function setAccessTokenAttr($data);
    abstract protected function doGetOpenID();
    abstract protected function setOpenIDAttr($data);
    abstract protected function doGetUserInfo();
    abstract protected function setUserInfoAttr($data);
}
